# -*- coding: utf-8 -*-
import sys
from pathlib import Path

from PySide6.QtCore import Qt, QPoint, QSettings, QStandardPaths, QTimer, QAbstractNativeEventFilter, QEvent
from PySide6.QtGui import QFont, QKeySequence, QShortcut, QIcon, QPixmap, QPainter, QColor, QTextCharFormat, QTextCursor, QTextDocument
from PySide6.QtWidgets import (
    QApplication,
    QMainWindow,
    QWidget,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QPushButton,
    QPlainTextEdit,
    QSlider,
    QSizeGrip,
    QMenu,
    QToolTip,
    QSystemTrayIcon,
    QLineEdit,
)


# Windows 全局热键过滤器
class WinHotkeyFilter(QAbstractNativeEventFilter):
    def __init__(self, callback):
        super().__init__()
        self.callback = callback

    def nativeEventFilter(self, eventType, message):
        if eventType != "windows_generic_MSG":
            return False, 0
        import ctypes
        from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM, POINT, DWORD

        class MSGSTRUCT(ctypes.Structure):
            _fields_ = [
                ("hwnd", HWND),
                ("message", UINT),
                ("wParam", WPARAM),
                ("lParam", LPARAM),
                ("time", DWORD),
                ("pt", POINT),
            ]
        try:
            msg = MSGSTRUCT.from_address(int(message))
        except Exception:
            return False, 0
        WM_HOTKEY = 0x0312
        WM_NCHITTEST = 0x0084
        # 处理全局热键
        if msg.message == WM_HOTKEY:
            self.callback(msg.wParam)
            return True, 0
        # 处理无边框窗口的尺寸调整命中测试（四边/四角可拖拽）
        if msg.message == WM_NCHITTEST:
            try:
                class RECT(ctypes.Structure):
                    _fields_ = [("left", ctypes.c_long), ("top", ctypes.c_long), ("right", ctypes.c_long), ("bottom", ctypes.c_long)]
                rect = RECT()
                ctypes.windll.user32.GetWindowRect(msg.hwnd, ctypes.byref(rect))
                pt = POINT()
                ctypes.windll.user32.GetCursorPos(ctypes.byref(pt))
                x, y = pt.x, pt.y
                margin = 8
                # 角落优先
                HTLEFT, HTRIGHT, HTTOP, HTBOTTOM = 10, 11, 12, 15
                HTTOPLEFT, HTTOPRIGHT, HTBOTTOMLEFT, HTBOTTOMRIGHT = 13, 14, 16, 17
                if abs(x - rect.left) <= margin and abs(y - rect.top) <= margin:
                    return True, HTTOPLEFT
                if abs(x - rect.right) <= margin and abs(y - rect.top) <= margin:
                    return True, HTTOPRIGHT
                if abs(x - rect.left) <= margin and abs(y - rect.bottom) <= margin:
                    return True, HTBOTTOMLEFT
                if abs(x - rect.right) <= margin and abs(y - rect.bottom) <= margin:
                    return True, HTBOTTOMRIGHT
                # 边缘
                if abs(x - rect.left) <= margin:
                    return True, HTLEFT
                if abs(x - rect.right) <= margin:
                    return True, HTRIGHT
                if abs(y - rect.top) <= margin:
                    return True, HTTOP
                if abs(y - rect.bottom) <= margin:
                    return True, HTBOTTOM
            except Exception:
                pass
            return False, 0
        return False, 0


class StickyNote(QMainWindow):
    def __init__(self, note_id: int, manager):
        super().__init__()
        self.setWindowTitle("透明记事本")
        # 无边框 + 透明背景 + 置顶
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.resize(360, 480)

        # 读取设置（按便签ID分组）
        self.settings = QSettings("DeskMemo", "StickyNote")
        self.note_id = note_id
        self.settings.beginGroup(f"note/{self.note_id}")
        self.manager = manager
        self._drag_pos: QPoint | None = None

        # 主容器（透明）
        container = QWidget(self)
        container.setObjectName("container")
        container.setStyleSheet(
            "#container{background: rgba(0,0,0,0); border: none;}"
        )
        self.setCentralWidget(container)

        root = QVBoxLayout(container)
        root.setContentsMargins(12, 12, 12, 12)
        root.setSpacing(8)

        # 顶部工具栏
        toolbar = QWidget(self)
        toolbar.setObjectName("toolbar")
        toolbar.setStyleSheet(
            "#toolbar{background: rgba(30,30,30,120); border-radius: 8px;}"
        )
        t_layout = QHBoxLayout(toolbar)
        t_layout.setContentsMargins(10, 6, 10, 6)
        t_layout.setSpacing(8)

        title = QLabel("透明记事本")
        title.setStyleSheet("color: white;")
        title.setFont(QFont("Microsoft YaHei", 10))
        t_layout.addWidget(title)

        t_layout.addStretch(1)

        # 透明度滑块
        opacity_label = QLabel("透明度")
        opacity_label.setStyleSheet("color: white;")
        t_layout.addWidget(opacity_label)

        self.opacity_slider = QSlider(Qt.Horizontal)
        self.opacity_slider.setRange(40, 100)  # 40%-100%
        self.opacity_slider.setFixedWidth(120)
        t_layout.addWidget(self.opacity_slider)
        self.opacity_slider.valueChanged.connect(self.on_opacity_change)
        # 悬停提示：透明度调整
        opacity_label.setToolTip("透明度：拖动滑块调整")
        self.opacity_slider.setToolTip("透明度：拖动滑块调整")

        # 字号滑块
        font_label = QLabel("字号")
        font_label.setStyleSheet("color: white;")
        t_layout.addWidget(font_label)

        self.font_slider = QSlider(Qt.Horizontal)
        self.font_slider.setRange(10, 24)
        self.font_slider.setFixedWidth(110)
        t_layout.addWidget(self.font_slider)
        self.font_slider.valueChanged.connect(self.on_font_size_change)
        # 悬停提示：字号调整
        font_label.setToolTip("字号：拖动滑块调整")
        self.font_slider.setToolTip("字号：拖动滑块调整")

        # 置顶切换
        self.pin_btn = QPushButton("置顶")
        self.pin_btn.setCheckable(True)
        self.pin_btn.setChecked(True)
        self.pin_btn.setStyleSheet(self._button_style())
        self.pin_btn.toggled.connect(self.toggle_on_top)
        t_layout.addWidget(self.pin_btn)
        # 悬停提示：置顶
        self.pin_btn.setToolTip("置顶：窗口始终在最前")

        # 点击穿透切换
        self.through_btn = QPushButton("穿透")
        self.through_btn.setCheckable(True)
        self.through_btn.setStyleSheet(self._button_style())
        self.through_btn.toggled.connect(self.toggle_click_through)
        t_layout.addWidget(self.through_btn)
        # 悬停提示：穿透快捷键
        self.through_btn.setToolTip("切换穿透（Ctrl+Shift+C），全局（Ctrl+Alt+C）")

        # 搜索栏（Ctrl+F 显示/隐藏）
        self.search_bar = QLineEdit()
        self.search_bar.setPlaceholderText("搜索")
        self.search_bar.setFixedWidth(140)
        self.search_bar.setStyleSheet(
            "color:white; background: rgba(255,255,255,30); border: none;"
            "border-radius:6px; padding:4px 8px;"
        )
        self.search_bar.hide()
        t_layout.addWidget(self.search_bar)
        # 悬停提示：搜索快捷键
        self.search_bar.setToolTip("搜索：Ctrl+F 显示/隐藏；F3 下一个；Shift+F3 上一个")

        # 最小化与关闭
        self.min_btn = QPushButton("—")
        self.min_btn.setStyleSheet(self._button_style())
        self.min_btn.clicked.connect(self.showMinimized)
        t_layout.addWidget(self.min_btn)
        self.min_btn.setToolTip("最小化")

        self.close_btn = QPushButton("×")
        self.close_btn.setStyleSheet(self._button_style())
        self.close_btn.clicked.connect(self.close)
        t_layout.addWidget(self.close_btn)
        self.close_btn.setToolTip("关闭")

        # 悬停提示：整栏快捷键速览
        toolbar.setToolTip(
            "快捷键：Ctrl+F 搜索；F3 下一个；Shift+F3 上一个；"
            "Ctrl+Shift+滚轮 调整窗口；Ctrl+Shift+0 恢复默认大小；"
            "Ctrl+Shift+C 切换穿透；Ctrl+Alt+Space 显示/隐藏；Ctrl+Alt+C 全局穿透；"
            "Ctrl+S 保存"
        )

        root.addWidget(toolbar)

        # 文本编辑（半透明背景）
        self.editor = QPlainTextEdit()
        self.editor.setPlaceholderText("在此输入你的便签内容……")
        self.editor.setStyleSheet(
            "QPlainTextEdit{background: rgba(30,30,30,160); color: white;"
            "border-radius: 10px; padding: 8px; border: 1px solid rgba(255,255,255,60);}"
        )
        self.editor.setFont(QFont("Microsoft YaHei", 11))
        root.addWidget(self.editor, 1)
        
        # 使用中文自定义右键菜单
        self.editor.setContextMenuPolicy(Qt.CustomContextMenu)
        self.editor.customContextMenuRequested.connect(self.show_context_menu)
        # 使用 Ctrl+Shift+滚轮 调整窗口大小
        self.editor.installEventFilter(self)
        
        # 手动保存快捷键 Ctrl+S
        self.save_shortcut = QShortcut(QKeySequence.Save, self.editor)
        self.save_shortcut.activated.connect(self.save_text)
        
        # 新增：穿透本地快捷键 Ctrl+Shift+C
        self.shortcut_through_toggle = QShortcut(QKeySequence("Ctrl+Shift+C"), self)
        self.shortcut_through_toggle.activated.connect(self.toggle_through_shortcut)
        self.shortcut_find = QShortcut(QKeySequence.Find, self)
        self.shortcut_find.activated.connect(self.toggle_search_bar)
        self.shortcut_find_next = QShortcut(QKeySequence("F3"), self)
        self.shortcut_find_next.activated.connect(self.find_next)
        self.shortcut_find_prev = QShortcut(QKeySequence("Shift+F3"), self)
        self.shortcut_find_prev.activated.connect(self.find_prev)
        # ESC 关闭搜索栏
        self.shortcut_esc_search = QShortcut(QKeySequence("Escape"), self)
        self.shortcut_esc_search.activated.connect(lambda: self.toggle_search_bar(force_hide=True))
        self.search_bar.textChanged.connect(self.on_search_text_changed)
        
        # 新增：窗口大小快捷键
        self.shortcut_win_grow = QShortcut(QKeySequence("Ctrl+Shift+="), self)
        self.shortcut_win_grow.activated.connect(lambda: self.resize_by_factor(1.1))
        self.shortcut_win_shrink = QShortcut(QKeySequence("Ctrl+Shift+-"), self)
        self.shortcut_win_shrink.activated.connect(lambda: self.resize_by_factor(0.9))
        self.shortcut_win_reset = QShortcut(QKeySequence("Ctrl+Shift+0"), self)
        self.shortcut_win_reset.activated.connect(self.reset_default_size)
        
        # 自动保存（防丢失）
        self._autosave = QTimer(self)
        self._autosave.setSingleShot(True)
        self._autosave.setInterval(1500)
        self._autosave.timeout.connect(self.save_text)
        self.editor.textChanged.connect(self._autosave.start)

        # 右下角尺寸拖拽柄
        size_grip = QSizeGrip(self)
        size_grip.setStyleSheet("background: transparent;")
        root.addWidget(size_grip, 0, Qt.AlignRight | Qt.AlignBottom)

        # 读取持久化内容
        self.load_state()

        # 允许拖动：仅在工具栏区域拖动
        toolbar.mousePressEvent = self._toolbar_mouse_press
        toolbar.mouseMoveEvent = self._toolbar_mouse_move

        # 启用无边框可缩放样式（配合 WM_NCHITTEST 支持四边/四角拖拽）
        self.enable_borderless_resize()

    def focusInEvent(self, event):
        # 记录当前活动便签
        if self.manager is not None:
            self.manager.active_note = self
        super().focusInEvent(event)

    def _button_style(self) -> str:
        return (
            "QPushButton{color:white; background: rgba(255,255,255,30);"
            "border: none; padding:4px 8px; border-radius:6px;}"
            "QPushButton:hover{background: rgba(255,255,255,60);}" 
            "QPushButton:checked{background: rgba(0,150,255,120);}"
        )

    def on_opacity_change(self, value: int):
        self.setWindowOpacity(value / 100.0)

    def toggle_on_top(self, checked: bool):
        flags = self.windowFlags()
        if checked:
            flags |= Qt.WindowStaysOnTopHint
        else:
            flags &= ~Qt.WindowStaysOnTopHint
        self.setWindowFlags(flags)
        self.show()

    # 顶部拖动
    def _toolbar_mouse_press(self, event):
        if event.button() == Qt.LeftButton:
            self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
            event.accept()

    def _toolbar_mouse_move(self, event):
        if self._drag_pos and event.buttons() & Qt.LeftButton:
            self.move(event.globalPosition().toPoint() - self._drag_pos)
            event.accept()

    # 使用中文右键菜单
    def show_context_menu(self, pos):
        menu = QMenu(self)
        doc = self.editor.document()
        cursor = self.editor.textCursor()

        # 手动保存
        act = menu.addAction("保存")
        act.setShortcut(QKeySequence.Save)
        act.triggered.connect(self.save_text)
        menu.addSeparator()

        act = menu.addAction("查找")
        act.setShortcut(QKeySequence.Find)
        act.triggered.connect(lambda: self.toggle_search_bar(force_show=True))
        menu.addSeparator()

        act = menu.addAction("撤销")
        act.setShortcut(QKeySequence.Undo)
        act.setEnabled(doc.isUndoAvailable())
        act.triggered.connect(self.editor.undo)

        act = menu.addAction("重做")
        act.setShortcut(QKeySequence.Redo)
        act.setEnabled(doc.isRedoAvailable())
        act.triggered.connect(self.editor.redo)

        menu.addSeparator()

        act = menu.addAction("剪切")
        act.setShortcut(QKeySequence.Cut)
        act.setEnabled(cursor.hasSelection())
        act.triggered.connect(self.editor.cut)

        act = menu.addAction("复制")
        act.setShortcut(QKeySequence.Copy)
        act.setEnabled(cursor.hasSelection())
        act.triggered.connect(self.editor.copy)

        act = menu.addAction("粘贴")
        act.setShortcut(QKeySequence.Paste)
        act.setEnabled(self.editor.canPaste())
        act.triggered.connect(self.editor.paste)

        act = menu.addAction("删除")
        act.setEnabled(cursor.hasSelection())
        act.triggered.connect(self.delete_selection)

        menu.addSeparator()

        act = menu.addAction("全选")
        act.setShortcut(QKeySequence.SelectAll)
        act.triggered.connect(self.editor.selectAll)

        menu.addSeparator()

        act = menu.addAction("复制全部")
        act.triggered.connect(self.copy_all)
        act = menu.addAction("清空")
        act.triggered.connect(self.clear_editor)

        # 新增：窗口大小控制
        menu.addSeparator()
        act = menu.addAction("窗口放大（Ctrl+Shift+滚轮↑）")
        act.triggered.connect(lambda: self.resize_by_factor(1.1))
        act = menu.addAction("窗口缩小（Ctrl+Shift+滚轮↓）")
        act.triggered.connect(lambda: self.resize_by_factor(0.9))
        act = menu.addAction("恢复默认大小（Ctrl+Shift+0）")
        act.triggered.connect(self.reset_default_size)
        
        # 穿透切换
        menu.addSeparator()
        act = menu.addAction("切换穿透（Ctrl+Shift+C）")
        act.triggered.connect(self.toggle_through_shortcut)

    def delete_selection(self):
        c = self.editor.textCursor()
        if c.hasSelection():
            c.removeSelectedText()
            self.editor.setTextCursor(c)

    def on_font_size_change(self, value: int):
        f = self.editor.font()
        f.setPointSize(value)
        self.editor.setFont(f)

    def copy_all(self):
        QApplication.clipboard().setText(self.editor.toPlainText())

    def clear_editor(self):
        self.editor.clear()
        self.save_text()

    # 搜索逻辑
    def toggle_search_bar(self, force_show: bool = False, force_hide: bool = False):
        if force_hide:
            self.search_bar.hide()
            self.editor.setExtraSelections([])
            return
        if force_show or self.search_bar.isHidden():
            self.search_bar.show()
            self.search_bar.setFocus()
            self.search_bar.selectAll()
        else:
            self.search_bar.hide()
            self.editor.setExtraSelections([])

    def resize_by_factor(self, factor: float):
        g = self.geometry()
        new_w = int(g.width() * factor)
        new_h = int(g.height() * factor)
        min_w, min_h = 240, 200
        max_w, max_h = 1600, 1400
        new_w = max(min_w, min(new_w, max_w))
        new_h = max(min_h, min(new_h, max_h))
        self.resize(new_w, new_h)
        # 立即持久化当前几何
        try:
            self.settings.setValue("geometry", self.saveGeometry())
        except Exception:
            pass

    def reset_default_size(self):
        self.resize(360, 480)
        try:
            self.settings.setValue("geometry", self.saveGeometry())
        except Exception:
            pass

    def enable_borderless_resize(self):
        # 为无边框窗体补充 WS_THICKFRAME 以允许系统级缩放
        try:
            import ctypes
            hwnd = int(self.winId())
            GWL_STYLE = -16
            WS_THICKFRAME = 0x00040000
            WS_MAXIMIZEBOX = 0x00010000
            WS_MINIMIZEBOX = 0x00020000
            user32 = ctypes.windll.user32
            GetWindowLong = user32.GetWindowLongW
            SetWindowLong = user32.SetWindowLongW
            style = GetWindowLong(hwnd, GWL_STYLE)
            style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX
            SetWindowLong(hwnd, GWL_STYLE, style)
        except Exception:
            pass

    def toggle_through_shortcut(self):
        cur = self.through_btn.isChecked()
        self.through_btn.setChecked(not cur)

    # 事件过滤：Ctrl+Shift+滚轮 缩放窗口
    def eventFilter(self, obj, event):
        if obj is self.editor and event.type() == QEvent.Wheel:
            mods = QApplication.keyboardModifiers()
            if (mods & Qt.ControlModifier) and (mods & Qt.ShiftModifier):
                delta = event.angleDelta().y()
                if delta > 0:
                    self.resize_by_factor(1.05)
                elif delta < 0:
                    self.resize_by_factor(0.95)
                return True
        return super().eventFilter(obj, event)

    def on_search_text_changed(self, text: str):
        self.highlight_matches(text.strip())

    def highlight_matches(self, query: str):
        extra = []
        if query:
            doc = self.editor.document()
            c = QTextCursor(doc)
            c.movePosition(QTextCursor.Start)
            fmt = QTextCharFormat()
            fmt.setBackground(QColor(255, 215, 0, 120))  # 金色高亮
            while True:
                c = doc.find(query, c)
                if c.isNull():
                    break
                sel = QPlainTextEdit.ExtraSelection()
                sel.cursor = c
                sel.format = fmt
                extra.append(sel)
        self.editor.setExtraSelections(extra)

    def find_next(self):
        q = self.search_bar.text().strip()
        if not q:
            return
        doc = self.editor.document()
        c = self.editor.textCursor()
        c = doc.find(q, c)
        if not c.isNull():
            self.editor.setTextCursor(c)

    def find_prev(self):
        q = self.search_bar.text().strip()
        if not q:
            return
        doc = self.editor.document()
        c = self.editor.textCursor()
        c = doc.find(q, c, QTextDocument.FindBackward)
        if not c.isNull():
            self.editor.setTextCursor(c)

    # 点击穿透
    def toggle_click_through(self, enabled: bool):
        self.set_click_through(enabled)

    def set_click_through(self, enabled: bool):
        try:
            import ctypes
            hwnd = int(self.winId())
            GWL_EXSTYLE = -20
            WS_EX_TRANSPARENT = 0x00000020
            WS_EX_LAYERED = 0x00080000
            user32 = ctypes.windll.user32
            GetWindowLong = user32.GetWindowLongW
            SetWindowLong = user32.SetWindowLongW
            ex = GetWindowLong(hwnd, GWL_EXSTYLE)
            if enabled:
                ex |= WS_EX_TRANSPARENT | WS_EX_LAYERED
            else:
                ex &= ~WS_EX_TRANSPARENT
            SetWindowLong(hwnd, GWL_EXSTYLE, ex)
        except Exception:
            pass

    # 持久化
    @property
    def memo_dir(self) -> Path:
        p = Path(QStandardPaths.writableLocation(QStandardPaths.AppDataLocation)) / "DeskMemo"
        try:
            p.mkdir(parents=True, exist_ok=True)
        except Exception:
            pass
        return p

    @property
    def memo_file(self) -> Path:
        return self.memo_dir / f"memo_{self.note_id}.txt"

    def load_state(self):
        # 文本
        if self.memo_file.exists():
            try:
                self.editor.setPlainText(self.memo_file.read_text(encoding="utf-8"))
            except Exception:
                pass
        else:
            # 兼容旧文件（首个便签沿用旧 memo.txt）
            legacy = self.memo_dir / "memo.txt"
            if self.note_id == 1 and legacy.exists():
                try:
                    self.editor.setPlainText(legacy.read_text(encoding="utf-8"))
                except Exception:
                    pass
        # 透明度
        opacity = self.settings.value("opacity", 85, type=int)
        self.opacity_slider.setValue(opacity)
        self.setWindowOpacity(opacity / 100.0)
        # 置顶
        on_top = self.settings.value("on_top", True, type=bool)
        self.pin_btn.setChecked(on_top)
        self.toggle_on_top(on_top)
        # 字号
        font_size = self.settings.value("font_size", 12, type=int)
        self.font_slider.setValue(font_size)
        self.on_font_size_change(font_size)
        # 穿透
        through = self.settings.value("click_through", False, type=bool)
        self.through_btn.setChecked(bool(through))
        self.set_click_through(bool(through))
        # 窗口位置大小
        if self.settings.contains("geometry"):
            self.restoreGeometry(self.settings.value("geometry"))

    def save_text(self):
        try:
            self.memo_file.write_text(self.editor.toPlainText(), encoding="utf-8")
        except Exception:
            pass
        # 保存提示
        QToolTip.showText(self.mapToGlobal(self.rect().center()), "已保存")

    def save_state(self):
        self.save_text()
        self.settings.setValue("opacity", self.opacity_slider.value())
        self.settings.setValue("on_top", self.pin_btn.isChecked())
        self.settings.setValue("geometry", self.saveGeometry())
        self.settings.setValue("font_size", self.font_slider.value())
        self.settings.setValue("click_through", self.through_btn.isChecked())

    def closeEvent(self, event):
        self.save_state()
        super().closeEvent(event)


class NoteApp:
    def __init__(self, app: QApplication):
        self.app = app
        self.notes: list[StickyNote] = []
        self.active_note: StickyNote | None = None
        # 托盘图标与菜单
        self.tray = QSystemTrayIcon(self._create_icon(), self.app)
        menu = QMenu()
        act_toggle = menu.addAction("显示/隐藏")
        act_toggle.triggered.connect(self.toggle_all)
        act_new = menu.addAction("新建便签")
        act_new.setShortcut(QKeySequence("Ctrl+N"))
        act_new.triggered.connect(self.new_note)
        # 新增：兜底取消所有穿透
        act_disable_through = menu.addAction("取消所有穿透")
        act_disable_through.triggered.connect(self.disable_all_through)
        menu.addSeparator()
        act_exit = menu.addAction("退出")
        act_exit.triggered.connect(self.quit)
        self.tray.setContextMenu(menu)
        self.tray.setToolTip("透明记事本")
        self.tray.activated.connect(self._tray_activated)
        self.tray.show()

        # 全局快捷键 Ctrl+Alt+Space 切换显示/隐藏；Ctrl+Alt+C 切换穿透
        self.HOTKEY_ID_TOGGLE = 1
        self.HOTKEY_ID_THROUGH = 2
        self._register_hotkey_space(self.HOTKEY_ID_TOGGLE)
        self._register_hotkey_c(self.HOTKEY_ID_THROUGH)
        self.filter = WinHotkeyFilter(self.on_hotkey)
        self.app.installNativeEventFilter(self.filter)

    def _create_icon(self) -> QIcon:
        pm = QPixmap(64, 64)
        pm.fill(Qt.darkBlue)
        painter = QPainter(pm)
        painter.setPen(Qt.white)
        painter.setFont(QFont("Microsoft YaHei", 36))
        painter.drawText(pm.rect(), Qt.AlignCenter, "记")
        painter.end()
        return QIcon(pm)

    def new_note(self):
        note_id = len(self.notes) + 1
        win = StickyNote(note_id, self)
        win.show()
        self.notes.append(win)
        self.active_note = win
        return win

    def toggle_all(self):
        any_visible = any(w.isVisible() for w in self.notes)
        for w in self.notes:
            if any_visible:
                w.hide()
            else:
                w.show()

    def _tray_activated(self, reason):
        if reason == QSystemTrayIcon.Trigger:
            self.toggle_all()

    def on_hotkey(self, hotkey_id):
        if hotkey_id == self.HOTKEY_ID_TOGGLE:
            self.toggle_all()
        elif hotkey_id == self.HOTKEY_ID_THROUGH:
            # 切换当前活动便签的穿透；无活动时，取消所有穿透
            if self.active_note:
                cur = self.active_note.through_btn.isChecked()
                self.active_note.through_btn.setChecked(not cur)
            else:
                self.disable_all_through()

    def quit(self):
        try:
            import ctypes
            ctypes.windll.user32.UnregisterHotKey(None, self.HOTKEY_ID_TOGGLE)
            ctypes.windll.user32.UnregisterHotKey(None, self.HOTKEY_ID_THROUGH)
        except Exception:
            pass
        for w in list(self.notes):
            if w:
                w.close()
        self.tray.hide()
        self.app.quit()

    def _register_hotkey_space(self, hotkey_id: int):
        import ctypes
        MOD_ALT = 0x0001
        MOD_CONTROL = 0x0002
        VK_SPACE = 0x20
        ctypes.windll.user32.RegisterHotKey(None, hotkey_id, MOD_ALT | MOD_CONTROL, VK_SPACE)

    def _register_hotkey_c(self, hotkey_id: int):
        import ctypes
        MOD_ALT = 0x0001
        MOD_CONTROL = 0x0002
        VK_C = 0x43
        ctypes.windll.user32.RegisterHotKey(None, hotkey_id, MOD_ALT | MOD_CONTROL, VK_C)

    def disable_all_through(self):
        for w in self.notes:
            if hasattr(w, 'through_btn'):
                w.through_btn.setChecked(False)
                w.set_click_through(False)

def main():
    app = QApplication(sys.argv)
    manager = NoteApp(app)
    manager.new_note()
    sys.exit(app.exec())


if __name__ == "__main__":
    main()